package com.ztesoft.zsmart.zcm.monitor.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;

import com.ztesoft.zsmart.core.utils.StringUtil;
import org.apache.log4j.Logger;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.UserInfo;
import com.ztesoft.zsmart.core.exception.BaseAppException;
import com.ztesoft.zsmart.core.exception.ExceptionHandler;

/**
 * ssh操作类
 * @author fan.jiaji
 *
 */
public class Ssh2Manager {
    
    
    /**
     * 日志组件
     */
    private Logger logger = Logger.getLogger(this.getClass());

    /**
     * 主机ip
     */
    private String host;

    /**
     * 用户名
     */
    private String user;

    /**
     * 密码
     */
    private String password;

    /**
     * 端口
     */
    private int port;

    /**
     * 会话
     */
    private Session session;

    /**
     * 文件列表
     */
    private File[] listFiles;
    
    
    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }
    

    /**
     * 构造函数
     * @param host 主机
     * @param user 用户
     * @param password 密码
     * @param port 端口
     */
    public Ssh2Manager(String host, String user, String password, int port) {
        
        this.host = host;
        this.user = user;
        this.password = password;
        this.port = port;
        
    }

    /**
     * 初始化会话
     * @throws BaseAppException
     */
    public void initialSession() throws BaseAppException {
        
        try {
            
            if (session == null) {
                JSch jsch = new JSch();
                session = jsch.getSession(user, host, port);
                session.setUserInfo(new UserInfo() {

                    public String getPassphrase() {
                        return null;
                    }

                    public String getPassword() {
                        return null;
                    }

                    public boolean promptPassword(String arg0) {
                        return false;
                    }

                    public boolean promptPassphrase(String arg0) {
                        return false;
                    }

                    public boolean promptYesNo(String arg0) {
                        return true;
                    }

                    public void showMessage(String arg0) {
                    }

                });
                session.setPassword(password);
                session.connect();
            }            
        } 
        catch (Exception e) {
            
            ExceptionHandler.publish("", e);
            
        }
        

    }

    /**
     * 关闭连接
     *
     * @throws BaseAppException 
     */
    public void close() throws BaseAppException {
        
        try {
            
            if (session != null && session.isConnected()) {
                session.disconnect();
                session = null;
            }            
        } 
        catch (Exception e) {
            
            ExceptionHandler.publish("", e);
        }
    }
    

    /**
     * 上传文件
     * @param localPath 本地路径
     * @param localFile 文件名
     * @param remotePath 远程主机目录
     * @param sftp sftp
     * @throws BaseAppException 
     */
    public void putFile2(String localPath, String localFile, String remotePath, ChannelSftp sftp) throws BaseAppException {
        try {
            
            sftp.put(localPath + File.separator + localFile, remotePath);
            
        } 
        catch (Exception e) {

            ExceptionHandler.publish("", e);
        }
        
    }
    
    
    
    /**
     * 下载文件
     * @param directory 远程主机目录
     * @param downloadFile 待下载的文件
     * @param saveFile 本地保存文件
     * @param sftp sftp
     * @throws BaseAppException 
     */
    public void download(String directory, String downloadFile, String saveFile, ChannelSftp sftp) throws BaseAppException  {
        
        try {
            sftp.cd(directory);
            File file = new File(saveFile);
            try (FileOutputStream fs = new FileOutputStream(file)) {
                sftp.get(downloadFile, fs);
            }
        } 
        catch (Exception e) {
            ExceptionHandler.publish("", e);
        }
    }

    /**
     * 下载文件
     * @param directory 远程主机目录
     * @param downloadFile 待下载的文件
     * @param saveFile 本地保存文件
     * @param sftp sftp
     * @throws SftpException 
     */
    public void getFile(String directory, String downloadFile, String saveFile, ChannelSftp sftp) throws SftpException {
        
        sftp.get(directory + "/" + downloadFile, saveFile);
        
    }

    /**
     * 获取主机目录下的文件列表
     * @param directory 远程主机目录
     * @param sftp sftp
     * @throws SftpException 
     */
    public void dirPath(String directory, ChannelSftp sftp) throws SftpException {
        
        @SuppressWarnings("unchecked")
        Vector<Object> v = sftp.ls(directory);
        
        for (Iterator<Object> iterator = v.iterator(); iterator.hasNext();) {
            Object object = iterator.next();
            
            logger.info(isDirectoryName(object.toString()));
            logger.info(getLastTokenName(object.toString()));
            
//            System.out.println(isDirectoryName(object.toString()));
//            System.out.println(getLastTokenName(object.toString()));
            
        }
    }
    
    /**
     * 对字符串进行符号分割
     * @param str 字符串
     * @return 目录名
     * @throws SftpException 
     */
    public String getLastTokenName(String str) throws SftpException {
        
        String directoryName = null;
//        ArrayList tokenList=new ArrayList();
        
        StringTokenizer st = new StringTokenizer(str, " ");
        
        while (st.hasMoreTokens()) {
//            System.out.println(st.nextToken());
            directoryName = st.nextToken();
//            tokenList.add(st.nextToken());
        }
        
        return directoryName;
    }
    
    
    
    /**
     * 记录是否目录
     * @param str 字符串
     * @return 是否是目录
     * @throws SftpException 
     */
    public boolean isDirectoryName(String str) throws SftpException {
        
        if (str.startsWith("d")) {
            return true;
        }
        return false;
    }

    
    /**
     * 下载目录
     * @param remoteDirectory 远程主机目录
     * @param localDirectory 本地目录
     * @param includes 包含的文件
     * @param excludes 排除的文件
     * @throws BaseAppException 
     */
    public void downloadFiles(String remoteDirectory, String localDirectory, String includes, String excludes) throws BaseAppException {
        
        Channel channelSftp = null;

        try {
            
            File f = new File(localDirectory);
            f.mkdirs();
            
            initialSession();
            channelSftp = getSession().openChannel("sftp");
            channelSftp.connect();
            ChannelSftp sftp = (ChannelSftp) channelSftp;
            @SuppressWarnings("unchecked")
            Vector<Object> v = sftp.ls(remoteDirectory);
            String str;
            for (Iterator<Object> iterator = v.iterator(); iterator.hasNext();) {
                Object object = iterator.next();
                str = getLastTokenName(object.toString());
                
                if ((!(".").equals(str)) && (!("..").equals(str))) {
                    
                    if (isDirectoryName(object.toString())) {
                        File file = new File(localDirectory + "/" + str);
                        file.mkdir();
                        downloadFiles(remoteDirectory + "/" + str, localDirectory + "/" + str, includes, excludes);                    
                    }
                    else {
                        if (checkIncludesAndExcludesDownload(str, includes, excludes)) {
                            getFile(remoteDirectory, str, localDirectory, sftp);
                        }                        
//                        System.out.println(object.toString());                        
                    }
                }
            }
            channelSftp.disconnect();
            
        } 
        catch (Exception e) {
            ExceptionHandler.publish("", e);
        }
        finally {
            
            if (channelSftp != null) {
                channelSftp.disconnect();
            }
        }        
    }
    
    /**
     * 校验包含排除条件
     * @param fileName 文件名
     * @param includes 包含后缀
     * @param excludes 排除后缀
     * @return 是否需要下载
     */
    private boolean checkIncludesAndExcludesDownload(String fileName, String includes, String excludes) {
        
        boolean needDownload = true;
        String fileNameStr = fileName.toLowerCase();
        
        try {
            
            //文件后缀名
            String regsEx = "\\.\\w+";
            
            if (includes != null && StringUtil.checkRegularStr(regsEx, includes)) {
                
                needDownload = false;                
                String includeStr = includes.toLowerCase();
                
                if (fileNameStr.endsWith(includeStr)) {
                    needDownload = true;
                }
                
            }
            
            if (excludes != null && StringUtil.checkRegularStr(regsEx, excludes)) {
                
                String excludeStr = excludes.toLowerCase();
                
                if (fileNameStr.endsWith(excludeStr)) {
                    needDownload = false;
                }                
            }    
            
        } 
        catch (Exception e) {
            //解析过程中出现任何异常，都认为是匹配出错了，不再校验成功失败，直接返回true进行下载
            
            return true;
            
        }        
        
        return needDownload;
        
    }
    
   
    /**
     * 上传目录
     * @param localDirectory  本地目录
     * @param remoteDirectory 远程主机目录
     * @throws BaseAppException 
     */
    public void uploadFiles2(String localDirectory, String remoteDirectory) throws BaseAppException {
        
        Channel channelSftp = null;
        
        try {
            
            initialSession();
            channelSftp = getSession().openChannel("sftp");
            channelSftp.connect();
            ChannelSftp sftp = (ChannelSftp) channelSftp;
            
            //先建目录
            createRemoteDir(remoteDirectory);
            
            
            File file = new File(localDirectory);
            
            if (file.isDirectory()) {
                listFiles = file.listFiles();
                for (File f : listFiles) {                
//                    System.out.println(f.getName());                
                    if (f.isDirectory()) {
                        uploadFiles2(localDirectory + File.separator + f.getName(), remoteDirectory + "/" + f.getName());
                    } 
                    else {
                        putFile2(localDirectory, f.getName(), remoteDirectory, sftp);
                    }                
                }  
            }
            else {
                putFile2(file.getParent(), file.getName(), remoteDirectory, sftp);
            }
            
          
            channelSftp.disconnect(); 
        } 
        catch (Exception e) {

            ExceptionHandler.publish("", e);

        }
        finally {
            
            if (channelSftp != null) {
                channelSftp.disconnect();
            }
        }
       
    }
    
    
    /**
     * 递归创建目录
     * @param remoteDirectory 远程主机目录
     * @throws BaseAppException 
     */
    public void createRemoteDir(String remoteDirectory) throws BaseAppException {
        
        Channel channelSftp = null;
        
        try {
            
            initialSession();
            channelSftp = getSession().openChannel("sftp");
            channelSftp.connect();
            ChannelSftp sftp = (ChannelSftp) channelSftp;
            
            try {
                
                @SuppressWarnings("rawtypes")
                Vector content = sftp.ls(remoteDirectory);
                if (content == null) {
                    sftp.mkdir(remoteDirectory);
                }
            } 
            catch (SftpException e) {
                if (e.getMessage().contains("No such file")) {
                    String parentRemoteDirectory = getParentPathOfRemotePath(remoteDirectory);
                    createRemoteDir(parentRemoteDirectory);                    
                }
                sftp.mkdir(remoteDirectory);
            }     
          
            channelSftp.disconnect(); 
        } 
        catch (Exception e) {
            ExceptionHandler.publish("", e);
        }
        finally {            
            if (channelSftp != null) {
                channelSftp.disconnect();
            }
        }       
    }
    
    /**
     * 获取远程目录的上一层目录
     * @param remotePath 远程目录
     * @return 上层目录
     */
    private String getParentPathOfRemotePath(String remotePath) {
        
        String str = remotePath.replace("\\", "/");
        if (str.endsWith("/")) {
            str = str.substring(0, str.lastIndexOf("/"));
        }
        str = str.substring(0, str.lastIndexOf("/"));
        
        return str;
        
    }


} 